#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBrain.h"
#include "AWTracerBrain.h"
#include "AWThreadedBrain.h"
#include "AWNOOSBrain.h"
#include "AWNOOSLearnerBrain.h"

#include "CaseBaseUtils.h"

#include "psm.h"

#include "loader.h"



FeatureTerm *AW_NOOSLearnerBrain::solve_problem_IBA_convener(FeatureTerm *problem,Sort *sort,Symbol *my_name,bool test)
{
	int i;
	char *str;
	AW_Message *m;
	Symbol *agent_name;
	List<Symbol> agent_names;
	FeatureTerm *my_prediction,*prediction,*JER,*f,*op;
	List<FeatureTerm> JERs;
	List<FeatureTerm> new_JERs;
	List<float> JER_Cs;
	List<FeatureTerm> self_CAs_historic,self_CEs_historic;
	int current_round;

	write_debug_report("[%s](C): IBA convener started.\n",my_name->get());

	/* Retrieve the set of other agents: */ 
	{
		List<Symbol> *l=get_friends();
		agent_names.Copy(*l);
		delete l;
	}

	/* Make the other agents to start their IBA-other methods: */ 
	agent_names.Rewind();
	while(agent_names.Iterate(agent_name)) {
		f=new FeatureTerm((char *)0,m_ontology->get_sort("request-iba-collaboration-message"),1,
						  "problem",new FeatureTerm(problem));

		str=f->toStringNOOS(m_memory);
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
		delete []str;
		delete f;
		enqueue_operator(op);
	} /* while */ 

	/* Solve the problem individually: */ 
	my_prediction=build_single_jer(problem,sort,my_name);
	JERs.Insert(my_prediction);

	/* Receive the solution from the others: */ 
	for(i=0;i<agent_names.Length();i++) {
		wait_message();
		m=get_message();
		prediction=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		JERs.Add(prediction);
		delete m;
	} /* for */ 

	/* Compute the confidence of the arguments: */ 
	IBA_compute_confidence(problem,&JERs,&JER_Cs,&agent_names);

	/* Show initial arguments: */ 
	current_round=0;
	{
		int i;
		FeatureTerm *f,*f2;
		char *s,*s2;

		write_debug_report("JERs in round %i\n",current_round);
		i=0;
		JERs.Rewind();
		while(JERs.Iterate(prediction)) {
			f=prediction->featureValueQuick("solution");
			f2=prediction->featureValueQuick("agent");
			s2=f->toStringNOOS(m_memory);
			write_debug_report("JER %i (%s), for solution %s\n",i,f2->getSymbol()->get(),s2);
			delete []s2;
			f=prediction->featureValueQuick("justification");
			s=f->toStringNOOS(m_memory);
			write_debug_report("%s\n",s);
			delete []s;
			i++;
		} /* while */ 
	}

	/* Start the IBA protocol: */ 
	{
		bool any_change=false;
		do {
			any_change=false;
			write_debug_report("[%s](C): Round %i of the IBA protocol starts.\n",my_name->get(),current_round);

			/* Pass the token: */ 
			agent_names.Rewind();
			while(agent_names.Iterate(agent_name)) {
				{
					FeatureTerm *JER;
					float *c;
					FeatureTerm *f2=FeatureTerm::SetFeatureTerm((Symbol *)0);

					JERs.Rewind();
					JER_Cs.Rewind();
					while(JERs.Iterate(JER) && JER_Cs.Iterate(c)) {
						f=new FeatureTerm((char *)0,m_ontology->get_sort("iba-prediction-confidence"),2,
																		 "prediction",new FeatureTerm(JER),
																		 "confidence",new FeatureTerm((Symbol *)0,*c,m_ontology));					
						f2->addSetValue(f);
					} /* while */ 

					f=new FeatureTerm((char *)0,m_ontology->get_sort("token-iba-message"),1,
									  "arguments",f2);
				}

				str=f->toStringNOOS(m_memory);
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
				delete []str;
				delete f;
				enqueue_operator(op);

				/* Wait till the agent finishes: */ 
				wait_message();
				m=get_message();
				{
					FeatureTerm *tmp=0,*counterargument=0;
					List<FeatureTerm> arguments;

					if (m->content->get()!=0) {
						tmp=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
					} /* if */ 

					if (tmp!=0) {
						any_change=true;

						if (tmp->isSet()) {
							List<FeatureTerm> l;
							l.Instance(*tmp->set_values_quick());
							l.Rewind();
							while(l.Iterate(counterargument)) arguments.Add(counterargument);
						} else {
							arguments.Add(tmp);
						} /* if */ 

						while(!arguments.EmptyP()) {
							counterargument=arguments.ExtractIni();

							/* Process counterarguments: */ 
							if (counterargument->getSort()==m_ontology->get_sort("problem-prediction")) {
								/* Substitute the agent's current prediction, and reevaluate its confidence: */ 
								new_JERs.Add(new FeatureTerm(counterargument));
							} /* if */ 

							if (counterargument->getSort()==m_ontology->get_sort("counterargument-message") ||
								counterargument->getSort()==m_ontology->get_sort("counterexample-message")) {
								AW_Message *m2;
								/* Send the counterargument to the appropriate agent: */ 
								/* request him for another prediction, and reevaluate its confidence */ 
								str=counterargument->toStringNOOS(m_memory);
								write_debug_report("[%s](C): Counterargument/example sent to %s.\n",my_name->get(),counterargument->featureValueQuick("agent")->getSymbol()->get());
								if (!counterargument->featureValueQuick("agent")->getSymbol()->cmp(my_name)) {
									op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
													   "receiver",counterargument->featureValue("agent"),
													   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
									delete []str;
									enqueue_operator(op);

									/* Wait till the agent finishes: */ 
									wait_message();
									m2=get_message();
									{
										write_debug_report("[%s](C): Reply received from %s.\n",my_name->get(),m2->sender->get());

										/* If there is a new prediction, add it to the "new_JERs" list: */ 
										FeatureTerm *tmp=0;
		
										if (m2->content->get()!=0) {
											tmp=FeatureTerm::fromStringNOOS(m2->content->get(),m_memory,m_ontology);
										} /* if */ 

										if (tmp!=0) {
											if (tmp->getSort()==m_ontology->get_sort("problem-prediction")) {
												/* Substitute the agent's current prediction, and reevaluate its confidence: */ 
												new_JERs.Add(new FeatureTerm(tmp));
											} /* if */ 
											delete tmp;
										} /* if */ 

									}
									delete m2;
								} else {
									/* The counterargument goes for me (the convener agent): */ 

									/* Receives a counterargument: */ 
									if (counterargument->getSort()==m_ontology->get_sort("counterargument-message")) {
										write_debug_report("[%s](C): received a counterargument.\n",my_name->get());	

										/* Consider whether to change my prediction: */ 
										if (local_confidence(counterargument->featureValueQuick("counterargument"),sort) > 
											local_confidence(my_prediction,sort)) {

											write_debug_report("[%s](C): The counterargument of the other agent has convinced me.\n",my_name->get());
											
											/* change my current prediction: */ 
											my_prediction=counterargument->featureValue("counterargument");
											new_JERs.Add(my_prediction);
										} /* if */ 
									} /* if */ 

									/* Receives a counterexample: */ 
									if (counterargument->getSort()==m_ontology->get_sort("counterexample-message")) {
										FeatureTerm *tmp;

										write_debug_report("[%s](C): received a counterexample.\n",my_name->get());	
										
										/* Retain the new case: */ 
										tmp=counterargument->featureValue("counterexample");
										write_debug_report("[%s](C): learnt case %s\n",m->receiver->get(),tmp->getName()->get());
										received_cases_IBA2A.Add(tmp);

										/* Generate a new prediction: */ 
										{
											FeatureTerm *old_prediction = my_prediction;
											Sort *sort=get_case_sort(m_ontology,problem->getSort());

											my_prediction = build_single_jer(problem,sort,my_name);
											new_JERs.Add(my_prediction);


											/* Check if anyone has changed opinion, for logging purposes: */ 
											{
												FeatureTerm *old_sol,*new_sol;
												old_sol=old_prediction->featureValueQuick("solution");
												new_sol=my_prediction->featureValueQuick("solution");

												if (!(*old_sol==*new_sol)) {
													char *s1,*s2;
													s1=old_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
													s2=my_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
													write_debug_report("[%s](C): I changed my mind because of a counterexample (%s to %s).\n",
																		my_name->get(),
																		s1,s2);
													delete []s1;
													delete []s2;
												} // if 
											}

										}
									} /* if */ 
							
								} /* if */ 
							} /* if */ 										
						} /* while */ 

						delete tmp;
						tmp=0;
					} /* if */ 
				}
				delete m;

				/* If any new predictions, compute their global confidence: */ 
				if (!new_JERs.EmptyP()) {
					List<float> new_JER_Cs;
					IBA_compute_confidence(problem,&new_JERs,&new_JER_Cs,&agent_names);
					FeatureTerm *new_JER;
					float *new_C,*old_C;
					int i,pos;
	
					write_debug_report("[%s](C): %i new predictions in this round, reevaluating them.\n",my_name->get(),new_JERs.Length());

					/* substitute the old predictions with the new ones: */ 
					while(!new_JERs.EmptyP()) {
						new_JER=new_JERs.ExtractIni();
						new_C=new_JER_Cs.ExtractIni();

						JERs.Rewind();
						pos=-1;
						i=0;
						while(JERs.Iterate(JER) && pos==-1) {
							if (JER->featureValueQuick("agent")->getSymbol()->cmp(new_JER->featureValueQuick("agent")->getSymbol())) {
								pos=i;
							} /* if */ 
							i++;
						} /* while */ 

						JER=JERs[pos];
						old_C=JER_Cs[pos];
						JERs.SetObj(pos,new_JER);
						JER_Cs.SetObj(pos,new_C);
						if (my_prediction==JER) my_prediction=new_JER;

						/* Check if anyone has changed opinion, for logging purposes: */ 
						{
							FeatureTerm *old_sol,*new_sol;
							old_sol=JER->featureValueQuick("solution");
							new_sol=new_JER->featureValueQuick("solution");

							if (!(*old_sol==*new_sol)) {
								char *s1,*s2;
								s1=JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								s2=new_JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								write_debug_report("[%s](C): Agent %s has changed its mind (%s to %s).\n",
													my_name->get(),
													JER->featureValueQuick("agent")->getSymbol()->get(),
													s1,s2);
								delete []s1;
								delete []s2;
							} // if 
						}

						delete JER;
						delete old_C;

					} /* while */ 
				} /* if */ 

			} /* while */ 

			/* Personally own the token: */ 
			write_debug_report("[%s](C): I have the token -----------------------------------\n",my_name->get());
			{
				/* Prepare all the messages I want to send: */ 
				FeatureTerm *counterargument;

				counterargument=IBA_generate_counterargument(problem,&JERs,&JER_Cs,my_name,&self_CAs_historic,&self_CEs_historic);
				if (counterargument!=0) {
					any_change=true;

					/* If it is a counterargument, then consider if changing my current prediction: */ 
					if (counterargument->getSort()==m_ontology->get_sort("counterargument-message")) {
						if (local_confidence(counterargument->featureValueQuick("counterargument"),sort) > 
							local_confidence(my_prediction,sort)) {
							/* change my current prediction: */ 
							write_debug_report("[%s](C): I change my current prediction.\n",my_name->get());
							my_prediction=counterargument->featureValue("counterargument");
							new_JERs.Add(my_prediction);
						} /* if */ 
					} /* if */ 


					if (counterargument->getSort()==m_ontology->get_sort("counterargument-message") ||
						counterargument->getSort()==m_ontology->get_sort("counterexample-message")) {
						AW_Message *m2;
						/* Send the counterargument to the appropriate agent: */ 
						/* request him for another prediction, and reevaluate its confidence */ 
						str=counterargument->toStringNOOS(m_memory);
						write_debug_report("[%s](C): Counterargument/example sent to %s.\n",my_name->get(),counterargument->featureValueQuick("agent")->getSymbol()->get());
						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",counterargument->featureValue("agent"),
										   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
						delete []str;
						enqueue_operator(op);

						/* Wait till the agent finishes: */ 
						wait_message();
						m2=get_message();
						{
							write_debug_report("[%s](C): Reply received from %s.\n",my_name->get(),m2->sender->get());

							/* If there is a new prediction, add it to the "new_JERs" list: */ 
							FeatureTerm *tmp=0;

							if (m2->content->get()!=0) {
								tmp=FeatureTerm::fromStringNOOS(m2->content->get(),m_memory,m_ontology);
							} /* if */ 

							if (tmp!=0) {
								if (tmp->getSort()==m_ontology->get_sort("problem-prediction")) {
									/* Substitute the agent's current prediction, and reevaluate its confidence: */ 
									new_JERs.Add(new FeatureTerm(tmp));
								} /* if */ 
								delete tmp;
							} /* if */ 

						}
						delete m2;
					} /* if */ 	

					delete counterargument;
					counterargument=0;
				} /* if */ 

				/* If any new predictions, compute their global confidence: */ 
				if (!new_JERs.EmptyP()) {
					List<float> new_JER_Cs;
					IBA_compute_confidence(problem,&new_JERs,&new_JER_Cs,&agent_names);
					FeatureTerm *new_JER;
					float *new_C,*old_C;
					int i,pos;

					write_debug_report("[%s](C): %i new predictions in this round, reevaluating them.\n",my_name->get(),new_JERs.Length());

					/* substitute the old predictions with the new ones: */ 
					while(!new_JERs.EmptyP()) {
						new_JER=new_JERs.ExtractIni();
						new_C=new_JER_Cs.ExtractIni();

						JERs.Rewind();
						pos=-1;
						i=0;
						while(JERs.Iterate(JER) && pos==-1) {
							if (JER->featureValueQuick("agent")->getSymbol()->cmp(new_JER->featureValueQuick("agent")->getSymbol())) {
								pos=i;
							} /* if */ 
							i++;
						} /* while */ 

						JER=JERs[pos];
						old_C=JER_Cs[pos];
						JERs.SetObj(pos,new_JER);
						JER_Cs.SetObj(pos,new_C);
						if (my_prediction==JER) my_prediction=new_JER;

						/* Check if anyone has changed opinion, for logging purposes: */ 
						{
							FeatureTerm *old_sol,*new_sol;
							old_sol=JER->featureValueQuick("solution");
							new_sol=new_JER->featureValueQuick("solution");

							if (!(*old_sol==*new_sol)) {
								char *s1,*s2;
								s1=JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								s2=new_JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								write_debug_report("[%s](C): Agent %s has changed its mind (%s to %s).\n",
													my_name->get(),
													JER->featureValueQuick("agent")->getSymbol()->get(),
													s1,s2);
								delete []s1;
								delete []s2;
							} // if 
						}

						delete JER;
						delete old_C;

					} /* while */ 
				} /* if */ 
			}

			current_round++;
		}while(any_change);
	}


	/* Inform the other agents that the protocol is over: */ 
	write_debug_report("[%s](C): Sending termination messages to the other agents.\n",my_name->get());
	agent_names.Rewind();
	while(agent_names.Iterate(agent_name)) {
		if (test) f=new FeatureTerm((char *)0,m_ontology->get_sort("reset-test-iba"),0);
			 else f=new FeatureTerm((char *)0,m_ontology->get_sort("reset-iba"),0);

		str=f->toStringNOOS(m_memory);
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
		delete []str;
		delete f;
		enqueue_operator(op);
	} /* while */ 
	for(i=0;i<agent_names.Length();i++) {
		wait_message();
		m=get_message();
		delete m;
	} /* for */ 

	/* Appply retention strategy: */ 
	if (!test) retain_cases(&received_cases_IBA2A,m_amal2_retention_strategy);
	received_cases_IBA2A.Delete();

	/* Decide final solution: */ 
	write_debug_report("[%s](C): Deciding final solution.\n",my_name->get());
	{
		int pos;
		FeatureTerm *solution_record;
		List<FeatureTerm> solutions;
		List<float> votes;
		FeatureTerm *solution;
		int selected;

		for(i=0;i<JERs.Length();i++) {
			solution=JERs[i]->featureValueQuick("solution");
			pos=solutions.Position(solution);
			if (pos==-1) {
				solutions.Add(new FeatureTerm(solution));
				votes.Add(new float(*JER_Cs[i]));
			} else {
				*votes[pos]=*votes[pos]+*JER_Cs[i];
			} /* if */ 		
		} /* for */ 

		for(i=0;i<solutions.Length();i++) {
			char *s;
			s=solutions[i]->toStringNOOS(m_memory);
			write_debug_report("%s -> %g\n",s,*votes[i]);
			delete []s;
		} /* for */ 

		selected=0;
		for(i=0;i<solutions.Length();i++) {
			if (*votes[i]>*votes[selected]) {
				selected=i;
			} /* if */ 
		} /* for */ 

		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction"),1,
										"solution",new FeatureTerm(solutions[selected]));
		return solution_record;
	}
} /* AW_NOOSLearnerBrain::solve_problem_IBA_convener */ 


void AW_NOOSLearnerBrain::solve_problem_IBA_other(FeatureTerm *problem,Sort *sort,Symbol *my_name,Symbol *convener_name,bool test)
{
	AW_Message *m;
	FeatureTerm *m_content;
	FeatureTerm *my_prediction=0;
	bool end;
	List<FeatureTerm> self_CAs_historic,self_CEs_historic;

	write_debug_report("[%s]: IBA other started (convened by %s).\n",my_name->get(),convener_name->get());


	/* Produce initial prediction: */ 
	{
		FeatureTerm *op;
		Sort *sort=get_case_sort(m_ontology,problem->getSort());
		char *s;

		my_prediction = build_single_jer(problem,sort,my_name);
		s=my_prediction->toStringNOOS(m_memory);

		/* Send back the solution: */ 
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(convener_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
		enqueue_operator(op);
		delete []s;	
	}


	/* Wait till I have the token or until termination message: */ 
	end=false;
	do{
		wait_message();
		m=get_message();
		m_content=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		
		/* Terminate protocol: */ 
		if (m_content->getSort()==m_ontology->get_sort("reset-iba") ||
			m_content->getSort()==m_ontology->get_sort("reset-test-iba")) {
			FeatureTerm *op;

			/* Appply retention strategy: */ 
			if (m_content->getSort()==m_ontology->get_sort("reset-iba"))
				retain_cases(&received_cases_IBA2A,m_amal2_retention_strategy);

			received_cases_IBA2A.Delete();
			/* Send back a confirmation: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol("(define (any))"),m_ontology));
			enqueue_operator(op);

			write_debug_report("[%s]: IBA protocol terminated.\n",my_name->get());			

			end=true;
		} /* if */ 
		
		/* Examine jutifications: */ 
		if (m_content->getSort()==m_ontology->get_sort("request-examination-message")) {
			FeatureTerm *op;
			FeatureTerm *problem;
			FeatureTerm *JERs,*JER;
			FeatureTerm *XERs;
			char *s;

			JERs=m_content->featureValue("prediction");
			problem=m_content->featureValue("problem");

			if (JERs==0 || problem==0) write_debug_report("em: ERROR 1\n");

			/* Examine the JER: */ 
			{
				Sort *sort=get_case_sort(m_ontology,problem->getSort());
				if (sort==0) write_debug_report("em: ERROR 2\n");

				XERs=FeatureTerm::SetFeatureTerm((Symbol *)0);

				if (JERs->isFeatureTerm()) {
					XERs->addSetValue(examine_JER(JERs,sort));
				} else {
					List<FeatureTerm> *l;
					l=JERs->set_values_quick();
					l->Rewind();
					while(l->Iterate(JER)) {
						XERs->addSetValue(examine_JER(JER,sort));
					} /* while */ 
				} /* if */ 

				s=XERs->toStringNOOS(m_memory);
				delete XERs;
			}

			/* Send back the solution: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
			enqueue_operator(op);
			delete []s;

			delete JERs;
			delete problem;
		} /* if */ 


		/* Receives a counterargument: */ 
		if (m_content->getSort()==m_ontology->get_sort("counterargument-message")) {
			FeatureTerm *op;
			char *s;

			write_debug_report("[%s]: received a counterargument.\n",my_name->get());	

			s=0;
			/* Consider whether to change my prediction: */ 
			if (local_confidence(m_content->featureValueQuick("counterargument"),sort) > 
				local_confidence(my_prediction,sort)) {

				write_debug_report("[%s]: The counterargument of the other agent has convinced me.\n",my_name->get());

				delete my_prediction;
				my_prediction=0;
				my_prediction=m_content->featureValue("counterargument");
				
				/* change my current prediction: */ 
				s=my_prediction->toStringNOOS(m_memory);
			} /* if */ 
			

			/* Send back a confirmation: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
			if (s!=0) delete []s;
			enqueue_operator(op);
		} /* if */ 


		/* Receives a counterexample: */ 
		if (m_content->getSort()==m_ontology->get_sort("counterexample-message")) {
			FeatureTerm *tmp;

			write_debug_report("[%s]: received a counterexample.\n",my_name->get());	
			
			/* Retain the new case: */ 
			tmp=m_content->featureValue("counterexample");
			write_debug_report("[%s]: learnt case %s\n",m->receiver->get(),tmp->getName()->get());
			received_cases_IBA2A.Add(tmp);

			/* Generate a new prediction: */ 
			{
				FeatureTerm *op,*old_prediction;
				Sort *sort=get_case_sort(m_ontology,problem->getSort());
				char *s;

				old_prediction=my_prediction;
				my_prediction = build_single_jer(problem,sort,my_name);
				s=my_prediction->toStringNOOS(m_memory);

				/* Check if anyone has changed opinion, for logging purposes: */ 
				if (old_prediction!=0) {
					FeatureTerm *old_sol,*new_sol;
					old_sol=old_prediction->featureValueQuick("solution");
					new_sol=my_prediction->featureValueQuick("solution");

					if (!(*old_sol==*new_sol)) {
						char *s1,*s2;
						s1=old_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
						s2=my_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
						write_debug_report("[%s]: I changed my mind because of a counterexample (%s to %s).\n",
											my_name->get(),
											s1,s2);
						delete []s1;
						delete []s2;
					} // if 
				}

				if (old_prediction!=0) delete old_prediction;

				/* Send back the solution: */ 
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(convener_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
				enqueue_operator(op);
				delete []s;	
			}
		} /* if */ 


		/* The agent owns the token: */ 
		if (m_content->getSort()==m_ontology->get_sort("token-iba-message")) {
			FeatureTerm *op;
			FeatureTerm *counterargument;
			FeatureTerm *f;
			char *s;

			write_debug_report("[%s]: I have the token -----------------------------------\n",my_name->get());
			{
				List<FeatureTerm> JERs;
				List<float> JER_Cs;

				{
					List<FeatureTerm> *l;
					FeatureTerm *JER,*C;

					l=m_content->featureValueQuick("arguments")->set_values();

					l->Rewind();
					while(l->Iterate(f)) {
						JER=f->featureValue("prediction");
						C=f->featureValue("confidence");
						JERs.Add(JER);
						JER_Cs.Add(new float(C->getFloat()));
						delete C;
					} /* while */ 

					delete l;
				}
				counterargument=IBA_generate_counterargument(problem,&JERs,&JER_Cs,my_name,&self_CAs_historic,&self_CEs_historic);
				
				if (counterargument!=0) {
					/* If it is a counterargument, then consider if changing my current prediction: */ 
					if (counterargument->getSort()==m_ontology->get_sort("counterargument-message")) {
						if (local_confidence(counterargument->featureValueQuick("counterargument"),sort) > 
							local_confidence(my_prediction,sort)) {
							FeatureTerm *tmp;
							/* change my current prediction: */ 
							write_debug_report("[%s]: I change my current prediction.\n",my_name->get());

							tmp=FeatureTerm::SetFeatureTerm();
							tmp->addSetValue(counterargument);
							tmp->addSetValue(counterargument->featureValue("counterargument"));
							counterargument=tmp;
						} /* if */ 
					} /* if */ 
				} /* if */ 
			}

			if (counterargument!=0) {
				s=counterargument->toStringNOOS(m_memory);
				delete counterargument;
			} else {
				s=0;
			} /* if */ 

			/* Send back a confirmation: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
			if (s!=0) delete []s;
			enqueue_operator(op);
		} /* if */ 

		delete m_content;
		delete m;
	}while(!end);

	if (my_prediction!=0) delete my_prediction;

} /* AW_NOOSLearnerBrain::solve_problem_IBA_other */ 




void AW_NOOSLearnerBrain::IBA_compute_confidence(FeatureTerm *problem,List<FeatureTerm> *JERs,List<float> *JER_Cs,List<Symbol> *agent_names)
{
	AW_Message *m;
	FeatureTerm *op;
	FeatureTerm *JER,*XER;
	List< List< FeatureTerm> > XERs;
	FeatureTerm *f;
	char *str;
	Symbol *agent_name;
	int i;

	/* Request XERs from all the other agents for all the JERs: */ 
	{
		FeatureTerm *JER_set=FeatureTerm::SetFeatureTerm((Symbol *)0);
		Symbol *s_tmp;

		JERs->Rewind();
		while(JERs->Iterate(JER)) {
			JER_set->addSetValue(new FeatureTerm(JER));
		} /* while */ 
		f=new FeatureTerm((char *)0,m_ontology->get_sort("request-examination-message"),2,
						  "problem",new FeatureTerm(problem),
						  "prediction",new FeatureTerm(JER_set));
		str=f->toStringNOOS(m_memory);
		s_tmp=new Symbol(str);

		agent_names->Rewind();
		while(agent_names->Iterate(agent_name)) {
			/* Send the problem: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s_tmp),m_ontology));
			enqueue_operator(op);
		} /* while */ 

		delete s_tmp;
		delete []str;
		delete f;
		delete JER_set;
	}

	/* Locally examine the JERs: */ 
	JERs->Rewind();
	i=0;
	while(JERs->Iterate(JER)) {
		XER=examine_JER(JER,get_case_sort(m_ontology,problem->getSort()));
		XERs.Add(new List<FeatureTerm>);
		XERs[i]->Add(XER);
		i++;
	} /* while */ 

	/* Receive the examination from all the other agents: */ 
	for(i=0;i<agent_names->Length();i++) {
		int j;
		/* Wait for the examinations of the agent: */ 
		wait_message();
		m=get_message();
		
		f=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		if (f->isFeatureTerm()) {
			XERs[0]->Add(new FeatureTerm(f));
		} else {
			List<FeatureTerm> *l;
			l=f->set_values_quick();
			j=0;
			l->Rewind();
			while(l->Iterate(XER)) {
				XERs[j]->Add(new FeatureTerm(XER));
				j++;
			} /* while */ 
		} /* if */ 	
		delete f;
		delete m;
	} /* for */ 

	for(i=0;i<JERs->Length();i++) {
		int j;
		if ((*JERs)[i]->featureValueQuick("solution")->getName()!=0) {
			write_debug_report("For JER%i (%s): ",i,(*JERs)[i]->featureValueQuick("solution")->getName()->get());
		} else {
			char *s;
			s=(*JERs)[i]->featureValueQuick("solution")->toStringNOOS();
			write_debug_report("For JER%i (%s): ",i,s);
			delete []s;
		} /* if */ 

		for(j=0;j<XERs[i]->Length();j++) {
			write_debug_report("(%i,%i) ",XERs[i]->operator [](j)->featureValueQuick("endorsing-cases")->getInt(),
										  XERs[i]->operator [](j)->featureValueQuick("counter-examples")->getInt());
		} /* for */ 
		write_debug_report("\n");
	} /* for */ 

	/* Compute the confidence values of the JERs: */ 
	JER_Cs->Delete();
	for(i=0;i<JERs->Length();i++) {
		int Y=0,N=0;
		int j;
		for(j=0;j<XERs[i]->Length();j++) {
			Y+=XERs[i]->operator [](j)->featureValueQuick("endorsing-cases")->getInt();
			N+=XERs[i]->operator [](j)->featureValueQuick("counter-examples")->getInt();
		} /* for */ 
		JER_Cs->Add(new float(float(Y)/float(1+Y+N)));
	} /* for */ 

	for(i=0;i<JER_Cs->Length();i++) {
		write_debug_report("C(%i) = %g\n",i,*((*JER_Cs)[i]));
	} /* for */ 

} /* AW_NOOSLearnerBrain::IBA_compute_confidence */ 




float AW_NOOSLearnerBrain::IBA_compute_confidence(FeatureTerm *problem,FeatureTerm *JER,List<Symbol> *agent_names)
{
	AW_Message *m;
	FeatureTerm *op;
	FeatureTerm *XER;
	List<FeatureTerm> XERs;
	FeatureTerm *f;
	char *str;
	Symbol *agent_name;
	int i;

	/* Request XERs from all the other agents for all the JERs: */ 
	{
		FeatureTerm *JER_set=FeatureTerm::SetFeatureTerm((Symbol *)0);
		Symbol *s_tmp;

		JER_set->addSetValue(new FeatureTerm(JER));
		f=new FeatureTerm((char *)0,m_ontology->get_sort("request-examination-message"),2,
						  "problem",new FeatureTerm(problem),
						  "prediction",new FeatureTerm(JER_set));
		str=f->toStringNOOS(m_memory);
		s_tmp=new Symbol(str);

		agent_names->Rewind();
		while(agent_names->Iterate(agent_name)) {
			/* Send the problem: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s_tmp),m_ontology));
			enqueue_operator(op);
		} /* while */ 

		delete s_tmp;
		delete []str;
		delete f;
		delete JER_set;
	}

	/* Locally examine the JERs: */ 
	XER=examine_JER(JER,get_case_sort(m_ontology,problem->getSort()));
	XERs.Add(XER);

	/* Receive the examination from all the other agents: */ 
	for(i=0;i<agent_names->Length();i++) {
		int j;
		/* Wait for the examinations of the agent: */ 
		wait_message();
		m=get_message();
		
		f=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		if (f->isFeatureTerm()) {
			XERs.Add(new FeatureTerm(f));
		} else {
			List<FeatureTerm> *l;
			l=f->set_values_quick();
			j=0;
			l->Rewind();
			while(l->Iterate(XER)) {
				XERs.Add(new FeatureTerm(XER));
				j++;
			} /* while */ 
		} /* if */ 	
		delete f;
		delete m;
	} /* for */ 

	write_debug_report("For unique JER (%s): ",JER->featureValueQuick("solution")->getName()->get());
	for(i=0;i<XERs.Length();i++) {
		write_debug_report("(%i,%i)\n",XERs[i]->featureValueQuick("endorsing-cases")->getInt(),
									   XERs[i]->featureValueQuick("counter-examples")->getInt());
	} /* for */ 

	/* Compute the confidence values of the JERs: */ 
	{
		int Y=0,N=0;
		int j;
		for(j=0;j<XERs.Length();j++) {
			Y+=XERs[j]->featureValueQuick("endorsing-cases")->getInt();
			N+=XERs[j]->featureValueQuick("counter-examples")->getInt();
		} /* for */ 
		write_debug_report("C = %g\n",float(Y)/float(1+Y+N));
		return float(Y)/float(1+Y+N);
	}
} /* AW_NOOSLearnerBrain::IBA_compute_confidence */ 





FeatureTerm *AW_NOOSLearnerBrain::IBA_generate_counterargument(FeatureTerm *problem,List<FeatureTerm> *JERs,List<float> *JER_Cs,Symbol *my_name,List<FeatureTerm> *self_CAs_historic,List<FeatureTerm> *self_CEs_historic)
{
	int i;
	List<FeatureTerm> l;
	List<float> l2;
	FeatureTerm *JER,*my_prediction=0;
	float *C,my_confidence=0;
	List<FeatureTerm> candidate_cas,candidate_ces;

	write_debug_report("[%s]: Generating counterarguments:\n",my_name->get());

	l.Instance(*JERs);
	l2.Instance(*JER_Cs);
	l.Rewind();
	l2.Rewind();
	while(l.Iterate(JER) && l2.Iterate(C)) {
		if (JER->featureValueQuick("agent")->getSymbol()->cmp(my_name)) {
			my_prediction=JER;
			my_confidence=*C;
		} /* if */ 
	} /* while */ 

	if (my_prediction!=0 && my_confidence!=0) {
		char *s;
		s=my_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
		write_debug_report("[%s]: my prediction is <%s,%g>:\n",my_name->get(),s,my_confidence);
		delete []s;
	} else {
		write_debug_report("[%s]: ERROR! cannot determine my prediction and confidence.\n",my_name->get());
	} /* if */ 	


	/* Test wether a counterargument or counterexample has to be generated: */ 
	l.Instance(*JERs);
	l2.Instance(*JER_Cs);
	l.Rewind();
	l2.Rewind();
	i=0;
	while(l.Iterate(JER) && l2.Iterate(C)) {
		if (!JER->featureValueQuick("agent")->getSymbol()->cmp(my_name)) {
			if (!(*(JER->featureValueQuick("solution"))==*(my_prediction->featureValueQuick("solution")))) {
				if ((*C)>=my_confidence) {

					FeatureTerm *f;
					write_debug_report("[%s]: Trying to generate a counterargument against %s:\n",my_name->get(),JER->featureValueQuick("agent")->getSymbol()->get());
					
					/* Generate counterargument: */ 
					{
						List<FeatureTerm> already_sent_arguments;
						self_CAs_historic->Rewind();
						while(self_CAs_historic->Iterate(f)) {
							if (f->featureValueQuick("agent")->getSymbol()->cmp(JER->featureValueQuick("agent")->getSymbol())) {
								already_sent_arguments.Add(f->featureValue("counterargument"));
							} /* if */ 
						} /* while */ 

						f=generate_attacking_JER(problem,JER,&already_sent_arguments,get_case_sort(m_ontology,problem->getSort()),my_name);
					}

					if (f!=0) {
						candidate_cas.Add(new FeatureTerm((char *)0,m_ontology->get_sort("counterargument-message"),2,
				   										  "counterargument",f,
														  "agent",new FeatureTerm(0,new Symbol(JER->featureValueQuick("agent")->getSymbol()),m_ontology)));
					} else {
						/* Generate counterexample: */ 
						{
							List<FeatureTerm> already_sent_cases;
							self_CEs_historic->Rewind();
							while(self_CEs_historic->Iterate(f)) {
								if (f->featureValueQuick("agent")->getSymbol()->cmp(JER->featureValueQuick("agent")->getSymbol())) {
									already_sent_cases.Add(f->featureValue("counterexample"));
								} /* if */ 
							} /* while */ 

							f=generate_counterexample(&already_sent_cases,JER,get_case_sort(m_ontology,problem->getSort()));
						}
						if (f!=0) {
							candidate_ces.Add(new FeatureTerm((char *)0,m_ontology->get_sort("counterexample-message"),2,
										  					  "counterexample",f,
															  "agent",new FeatureTerm(0,new Symbol(JER->featureValueQuick("agent")->getSymbol()),m_ontology)));
						} /* if */ 

					} /* if */ 
				
				} /* if */ 
			} /* if */ 
		} /* if */ 
		i++;
	} /* while */ 


	write_debug_report("[%s]: I've generated %i CAs and %i CEs, now choosing the best one...\n",my_name->get(),candidate_cas.Length(),candidate_ces.Length());

	if (candidate_cas.Length()>0) {
		if (candidate_cas.Length()==1) {
			FeatureTerm *tmp;
			tmp=candidate_cas.ExtractIni();
			self_CAs_historic->Add(new FeatureTerm(tmp));
			return tmp;
		} else {
			/* choose that CA with most support: */ 
			FeatureTerm *tmp;
			int i;
			float max_C=0,local_C;
			FeatureTerm *max_f=0;

			candidate_cas.Rewind();
			i=0;
			while(candidate_cas.Iterate(tmp)) {
				local_C=local_confidence(tmp->featureValueQuick("counterargument"),get_case_sort(m_ontology,problem->getSort()));
				if (max_f==0 || local_C>max_C) {
					max_C=local_C;
					max_f=tmp;
				} /* if */ 
				i++;
			} /* while */ 

			write_debug_report("[%s]: Selected counterargument against %s with C=%g\n",my_name->get(),max_f->featureValueQuick("agent")->getSymbol()->get(),max_C);

			self_CAs_historic->Add(new FeatureTerm(max_f));

			return new FeatureTerm(max_f);
		} /* if */ 
	} /* if */ 

	if (candidate_ces.Length()>0 ){
		if (candidate_ces.Length()==1) {
			FeatureTerm *tmp;
			tmp=candidate_ces.ExtractIni();
			self_CEs_historic->Add(new FeatureTerm(tmp));
			return tmp;
		} else {
			/* Choose that CE that contradicts the prediction with the lowest confidence: */ 
			FeatureTerm *tmp;
			float min_C,current_C;
			FeatureTerm *min_f;
			Symbol *min_agent=0,*current_agent=0;
			Symbol *agent;

			candidate_ces.Rewind();
			while(candidate_ces.Iterate(tmp)) {
				agent=tmp->featureValueQuick("agent")->getSymbol();
				l.Instance(*JERs);
				l2.Instance(*JER_Cs);
				l.Rewind();
				l2.Rewind();
				current_C=0;
				current_agent=0;
				while(l.Iterate(JER) && l2.Iterate(C)) {
					if (JER->featureValueQuick("agent")->getSymbol()->cmp(agent)) {
						current_C=*C;
						current_agent=JER->featureValueQuick("agent")->getSymbol();
					} /* if */ 
				} /* while */ 

				if (current_agent!=0) {
					if (min_agent==0 || current_C<min_C) {
						min_agent=current_agent;
						min_C=current_C;
						min_f=tmp;
					} /* if */ 
				} /* if */ 

			} /* while */ 

			write_debug_report("[%s]: Selected counterexample against %s with C=%g\n",my_name->get(),min_agent->get(),min_C);

			self_CEs_historic->Add(new FeatureTerm(min_f));

			return new FeatureTerm(min_f);
		} /* if */ 
	} /* if */ 

	return 0;
} /* AW_NOOSLearnerBrain::IBA_generate_counterargument */ 


